/*
 * Utility functions for process management. 
 *
 * Note: in Lab1, only one process (i.e., our user application) exists. Therefore, 
 * PKE OS at this stage will set "current" to the loaded user application, and also
 * switch to the old "current" process after trap handling.
 */

#include "riscv.h"
#include "strap.h"
#include "config.h"
#include "process.h"
#include "elf.h"
#include "string.h"
#include "vmm.h"
#include "pmm.h"
#include "memlayout.h"
#include "spike_interface/spike_utils.h"

//Two functions defined in kernel/usertrap.S
extern char smode_trap_vector[];
extern void return_to_user(trapframe *, uint64 satp);

// current points to the currently running user-mode application.
process* current = NULL;

// start virtual address of our simple heap.
uint64 g_ufree_page = USER_FREE_ADDRESS_START;

//
// switch to a user-mode process
//
void switch_to(process* proc) {
  assert(proc);
  current = proc;

  write_csr(stvec, (uint64)smode_trap_vector);
  // set up trapframe values that smode_trap_vector will need when
  // the process next re-enters the kernel.
  proc->trapframe->kernel_sp = proc->kstack;      // process's kernel stack
  proc->trapframe->kernel_satp = read_csr(satp);  // kernel page table
  proc->trapframe->kernel_trap = (uint64)smode_trap_handler;

  // set up the registers that strap_vector.S's sret will use
  // to get to user space.

  // set S Previous Privilege mode to User.
  unsigned long x = read_csr(sstatus);
  x &= ~SSTATUS_SPP;  // clear SPP to 0 for user mode
  x |= SSTATUS_SPIE;  // enable interrupts in user mode

  write_csr(sstatus, x);

  // set S Exception Program Counter to the saved user pc.
  write_csr(sepc, proc->trapframe->epc);

  //make user page table
  uint64 user_satp = MAKE_SATP48(proc->pagetable);//由于用户页表是sv48的 所以要用MAKE_SATP48

  // switch to user mode with sret.
  return_to_user(proc->trapframe, user_satp);
}
uint64 num_RUNNING=0;
uint64 num_FREE=0;
uint64 num_READY=0;
uint64 num_BLOCKED=0;
uint64 num_ZOMBIE=0;
void psinfo(uint64 pid)
{
        sprint("-----进程信息---------\n");
        sprint("进程PID :  %d\n", pid);
        sprint("进程状态:  ");
        if(procs[pid].status==FREE)sprint("FREE\n");
        if(procs[pid].status==READY)sprint("READY\n");
        if(procs[pid].status==RUNNING)sprint("RUNNING\n");
        if(procs[pid].status==BLOCKED)sprint("BLOCKED\n");
        if(procs[pid].status==ZOMBIE)sprint("ZOMBIE\n");
    
        if(procs[pid].status==FREE)num_FREE++;
        if(procs[pid].status==READY)num_READY++;
        if(procs[pid].status==RUNNING)num_RUNNING++;
        if(procs[pid].status==BLOCKED)num_BLOCKED++;
        if(procs[pid].status== ZOMBIE)num_ZOMBIE++;

        sprint("运行数:  %d\n",num_RUNNING);
        sprint("空闲数:  %d\n",num_FREE);
        sprint("就绪数:  %d\n",num_READY);
        sprint("阻塞数:  %d\n",num_BLOCKED);
        sprint("僵尸数:  %d\n",num_ZOMBIE);
        sprint("-----进程信息---------\n");
}
​